package net.cassite.pure.ioc.handlers.type;

import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.Set;

import net.cassite.pure.ioc.*;
import net.cassite.pure.ioc.annotations.Default;
import net.cassite.pure.ioc.annotations.Wire;
import net.cassite.pure.ioc.handlers.TypeAnnotationHandler;
import net.cassite.pure.ioc.handlers.TypeHandlerChain;
import net.cassite.style.Style;
import net.cassite.style.aggregation.Aggregation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Handler for Wire annotation. <br>
 * if the class extends from AutoWire, this would simply return <br>
 * else, invoke AutoWire.wire with current scope and retrieved object
 *
 * @author wkgcass
 * @see Wire
 */
public class TypeWireHandler implements TypeAnnotationHandler {

        private static final Logger LOGGER = LoggerFactory.getLogger(TypeWireHandler.class);
        private static final Set<Class<? extends Annotation>> ignoringAnnotations = new HashSet<>();

        public static void ignoreWhenMeetingAnnotation(Class<? extends Annotation> anno) {
                ignoringAnnotations.add(anno);
        }

        @Override
        public boolean canHandle(Annotation[] annotations) {
                return true;
        }

        @Override
        public Object handle(Scope scope, Class<?> cls, Class<?> expectedClass, TypeHandlerChain chain) throws AnnotationHandlingException {
                LOGGER.debug("Entered TypeWireHandler with args: \n\tcls:\t{}\n\tchain:\t{}", cls, chain);
                Object inst = chain.next().handle(scope, cls, expectedClass, chain);

                if (!AutoWire.class.isAssignableFrom(cls) && Style.avoidNull(Aggregation.$(ignoringAnnotations).forEach(ac -> {
                        if (cls.isAnnotationPresent(ac)) return Style.BreakWithResult(false);
                        return true;
                }), true)) {
                        LOGGER.debug("start handling with TypeWireHandler");
                        try {
                                AutoWire.wire(scope, inst);
                        } catch (ConstructingMultiSingletonException ignore) {
                        }
                }
                return inst;
        }
}
